import React from 'react';
import { Icon, Popover } from 'antd';
import { getPosY } from './utils';
import styles from './index.module.less';

export default function VolumeBar(props) {
    const { audio } = props;

    const volumeBarRef = React.useRef();
    const [state, setState] = React.useState({ currentVolume: 1, currentVolumePos: '100%' });
    const [muted, setMuted] = React.useState(false);
    const finalVolumeRef = React.useRef(1);
    const isDraggingRef = React.useRef();

    let volumeAnimationTimer = 0;

    const getCurrentVolume = event => {
        if (!volumeBarRef.current) {
            return {
                currentVolume: audio.volume,
                currentVolumePos: state.currentVolumePos
            };
        }

        const volumeBarRect = volumeBarRef.current.getBoundingClientRect();
        const maxRelativePos = volumeBarRect.height;
        const relativePos = maxRelativePos - (getPosY(event) - volumeBarRect.top);
        let currentVolume;
        let currentVolumePos;

        if (relativePos < 0) {
            currentVolume = 0;
            currentVolumePos = '0%';
        } else if (relativePos > volumeBarRect.height) {
            currentVolume = 1;
            currentVolumePos = '100%';
        } else {
            currentVolume = relativePos / maxRelativePos;
            currentVolumePos = `${(relativePos / maxRelativePos) * 100}%`;
        }

        return { currentVolume, currentVolumePos };
    };

    const handleContextMenu = event => {
        event.preventDefault();
    };

    const handleWindowMouseOrTouchMove = event => {
        event.preventDefault();
        event.stopPropagation();
        // Prevent Chrome drag selection bug
        const windowSelection = window.getSelection();
        if (windowSelection && windowSelection.type === 'Range') {
            windowSelection.empty();
        }

        if (isDraggingRef.current) {
            const { currentVolume, currentVolumePos } = getCurrentVolume(event);
            audio.volume = currentVolume;
            setState({ ...state, currentVolumePos });
        }
    };

    const handleAudioVolumeChange = e => {
        const { volume, muted: audioMuted } = e.target;
        if (audioMuted || volume <= 0) {
            if (audioMuted && volume !== finalVolumeRef.current) {
                setMuted(false);
                audio.muted = false;
            } else {
                setMuted(true);
                audio.muted = true;
            }
        } else {
            setMuted(false);
            audio.muted = false;
        }
        finalVolumeRef.current = volume;
        if (isDraggingRef.current) return;
        const params = {
            ...state,
            hasVolumeAnimation: true,
            currentVolumePos: audioMuted ? '0%' : `${((volume / 1) * 100 || 0).toFixed(2)}%`
        };
        setState(params);
        clearTimeout(volumeAnimationTimer);
        volumeAnimationTimer = setTimeout(() => {
            setState({ ...params, hasVolumeAnimation: false });
        }, 100);
    };

    const handleWindowMouseOrTouchUp = event => {
        event.stopPropagation();
        isDraggingRef.current = false;

        if (event instanceof MouseEvent) {
            window.removeEventListener('mousemove', handleWindowMouseOrTouchMove);
            window.removeEventListener('mouseup', handleWindowMouseOrTouchUp);
        } else {
            window.removeEventListener('touchmove', handleWindowMouseOrTouchMove);
            window.removeEventListener('touchend', handleWindowMouseOrTouchUp);
        }
    };

    const handleVolumeControlMouseOrTouchDown = event => {
        event.stopPropagation();
        const { currentVolume, currentVolumePos } = getCurrentVolume(event.nativeEvent);
        audio.volume = currentVolume;
        isDraggingRef.current = true;
        setState({ ...state, currentVolumePos });

        if (event.nativeEvent instanceof MouseEvent) {
            window.addEventListener('mousemove', handleWindowMouseOrTouchMove);
            window.addEventListener('mouseup', handleWindowMouseOrTouchUp);
        } else {
            window.addEventListener('touchmove', handleWindowMouseOrTouchMove);
            window.addEventListener('touchend', handleWindowMouseOrTouchUp);
        }
    };

    const handleMutedChange = () => {
        if (audio.volume === 0) {
            audio.muted = true;
            setMuted(true);
        } else {
            audio.muted = !muted;
            setMuted(!muted);
        }
    };

    React.useEffect(() => {
        audio.addEventListener('volumechange', handleAudioVolumeChange);
        return () => {
            audio.removeEventListener('volumechange', handleAudioVolumeChange);
            clearTimeout(volumeAnimationTimer);
        };
    }, []);

    const content = (
        <div
            className={styles.volumeBarWrap}
            onMouseDown={handleVolumeControlMouseOrTouchDown}
            onTouchStart={handleVolumeControlMouseOrTouchDown}
            onContextMenu={handleContextMenu}
            ref={volumeBarRef}
        >
            <div className={styles.volumeBar}>
                <div className={styles.volumeIndicator} style={{ bottom: state.currentVolumePos }} />
                <div className={styles.volumeFilled} style={{ height: state.currentVolumePos }} />
            </div>
        </div>
    );

    return (
        <Popover content={content} trigger="hover">
            <Icon
                type={muted ? 'pause-circle' : 'sound'}
                style={{ fontSize: 20, marginLeft: 10, marginRight: 10 }}
                onClick={handleMutedChange}
            />
        </Popover>
    );
}
